package org.hepeng.workx.exception.translate;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.hepeng.workx.util.proxy.Invocation;
import org.hepeng.workx.util.proxy.Invoker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author he peng
 */
public class ExceptionTranslatorInvoker implements Invoker {

    private Object nativeBean;
    private ExceptionTranslateMethodResolver methodResolver;

    public ExceptionTranslatorInvoker(Object nativeBean, ExceptionTranslateMethodResolver methodResolver) {
        Assert.notNull(nativeBean , "nativeBean must not be null");
        Assert.notNull(methodResolver , "methodResolver must not be null");
        this.nativeBean = nativeBean;
        this.methodResolver = methodResolver;
    }

    @Override
    public Object invoke(Invocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Object result;

        try {
            if (methodResolver.hasTranslator(method)) {
                try {
                    method.setAccessible(true);
                    result = method.invoke(this.nativeBean , invocation.getArgs());
                } catch (Throwable t) {
                    Logger logger = LoggerFactory.getLogger(this.nativeBean.getClass());
                    logger.error(t.getMessage() , t);

                    t = ExceptionUtils.getRootCause(t);
                    ExceptionTranslateMethodResolver.ExceptionTranslatorReflectInvoker invoker =
                            this.methodResolver.getInvoker(t.getClass());

                    if (Objects.isNull(invoker)) {
                        t = new RuntimeException(t);
                    }

                    result = invoker.invoke(t);
                }
            } else {
                result = method.invoke(this.nativeBean , invocation.getArgs());
            }
        } catch (Throwable t) {
            throw t;
        }
        return result;
    }
}
